package com.nasarius.bank.scorecard.web.controller.user;

import java.io.IOException;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomCollectionEditor;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.nasarius.bank.scorecard.dao.BankDetailsDAO;
import com.nasarius.bank.scorecard.dao.BankFactorsActualDAO;
import com.nasarius.bank.scorecard.dao.BankFactorsDAO;
import com.nasarius.bank.scorecard.dao.FactorsDAO;
import com.nasarius.bank.scorecard.dao.SurveyAnswersDAO;
import com.nasarius.bank.scorecard.domain.BankDetails;
import com.nasarius.bank.scorecard.domain.BankFactors;
import com.nasarius.bank.scorecard.domain.BankFactorsActual;
import com.nasarius.bank.scorecard.domain.Factors;
import com.nasarius.bank.vo.BankResultVO;
import com.nasarius.bank.vo.FactorScoreCardVO;
import com.nasarius.bank.vo.FactorTimeVO;
import com.nasarius.bank.vo.FactorTimerListVO;
import com.nasarius.bank.vo.SearchVO;
@Controller
public class SearchController {
	 /** Logger that is available to subclasses */
	 protected final Log LOG = LogFactory.getLog(getClass());

	@Autowired 
	private BankFactorsActualDAO bankFactorsActualDAO;
	@Autowired
	private BankDetailsDAO bankDetailsDAO;
	@Autowired
	private BankFactorsDAO bankFactorsDAO;
	@Autowired
	private FactorsDAO factorsDAO;
	@Autowired
	private SurveyAnswersDAO surveyAnswersDAO;

	public void setBankFactorsActualDAO(
			BankFactorsActualDAO bankFactorsActualDAO) {
		this.bankFactorsActualDAO = bankFactorsActualDAO;
	}

	public BankDetailsDAO getBankDetailsDAO() {
		return bankDetailsDAO;
	}

	public void setBankDetailsDAO(BankDetailsDAO bankDetailsDAO) {
		this.bankDetailsDAO = bankDetailsDAO;
	}

	public BankFactorsDAO getBankFactorsDAO() {
		return bankFactorsDAO;
	}

	public void setBankFactorsDAO(BankFactorsDAO bankFactorsDAO) {
		this.bankFactorsDAO = bankFactorsDAO;
	}

	public BankFactorsActualDAO getBankFactorsActualDAO() {
		return bankFactorsActualDAO;
	}

	@InitBinder
	protected void initBinder(ServletRequestDataBinder binder) {
		binder.registerCustomEditor(List.class, new CustomCollectionEditor(
				List.class));
		binder.registerCustomEditor(Date.class, new CustomDateEditor(
				new SimpleDateFormat("dd/MM/yyyy"), true));
	}

	@ModelAttribute
	public SearchVO newRequest(@RequestParam(required = false) String searchId,
			Model model) {
		SearchVO searchVO = new SearchVO();
		return searchVO;
	}

	@RequestMapping(value = "/search/form", method = RequestMethod.GET)
	public void form(SearchVO searchVO, Model model) {
		List<BankDetails> activeBankDetails = bankDetailsDAO
				.selectAllAuthorizedBankDetails(SecurityContextHolder
						.getContext().getAuthentication().getName());
		//	bankDetailsDAO
		//	.selectAllActiveBankDetails();
		
		List<Factors> allFactors = factorsDAO.selectAllFactors();
		model.addAttribute("activeBankDetails", activeBankDetails);
		model.addAttribute("allFactors", allFactors);
	}

/*	@RequestMapping(value = "/search/result", method = RequestMethod.GET)
	public void result(SearchVO searchVO, Model model) {
		String view=null;
		List<BankDetails> activeBankDetails =  bankDetailsDAO
		.selectAllAuthorizedBankDetails(SecurityContextHolder
				.getContext().getAuthentication().getName());
	//	bankDetailsDAO
		//.selectAllActiveBankDetails();//
		HashMap<Date, Date> factorTimeMap = new HashMap<Date, Date>();
		List<FactorTimeVO> factorTimeList = new ArrayList<FactorTimeVO>();
		Map<String,BankDetails> bankNameMap= new HashMap<String, BankDetails>();
		for(BankDetails bank:activeBankDetails){
			bankNameMap.put(bank.getBankcode(), bank);
		}
		List<BankDetails> banks=new ArrayList<BankDetails>(); 
		for(String bankCode:searchVO.getBankIds()){
			banks.add(bankNameMap.get(bankCode));
		}
		List<FactorScoreCardVO> factorScoreCardVOs = new ArrayList<FactorScoreCardVO>();
		for (String factorId : searchVO.getFactorsIds()) {
			FactorScoreCardVO factorScoreCardVO = new FactorScoreCardVO();
			List<BankFactorsActual> bankFactorsActualList = bankFactorsActualDAO
					.bankFactorsActualByFactor(factorId, searchVO.getFromDt(),
							searchVO.getToDt());
			if(bankFactorsActualList == null || (bankFactorsActualList != null && bankFactorsActualList.isEmpty())){
				List<SurveyAnswers> surveyAnswersActualList = surveyAnswersDAO
				.surveyAnswersByFactor(factorId, searchVO.getFromDt(),
						searchVO.getToDt());
				convertSurveyToBankActual(bankFactorsActualList,
						surveyAnswersActualList);
			}
			List<BankFactors> bankFactorsList = bankFactorsDAO
					.bankFactorsByFactor(factorId, searchVO.getFromDt(),
							searchVO.getToDt());
			Map<Integer, BankFactors> factorMap = new HashMap<Integer, BankFactors>();
			Map<String, BankFactorsActual> bankfactorActualMap = new HashMap<String, BankFactorsActual>();
			for (BankFactors bankfactor : bankFactorsList) {
				factorMap.put(bankfactor.getFactorid(), bankfactor);
				factorScoreCardVO.setFactorName(bankfactor
						.getFactorName());
			}
			for (BankFactorsActual bankfactorActual : bankFactorsActualList) {
				if(searchVO.getBankIds().contains(bankfactorActual.getBankcode()));
				bankfactorActualMap.put(bankfactorActual.getBankcode(),
						bankfactorActual);
			}
			List<BankScoreCardVO> bankScoreCards = new ArrayList<BankScoreCardVO>();
			for (BankFactorsActual bankfactorActual : bankFactorsActualList) {
				if(searchVO.getBankIds().contains(bankfactorActual.getBankcode())){
					BankScoreCardVO bankScoreCardVO = new BankScoreCardVO();
					bankScoreCardVO.setBankname(bankNameMap.get(bankfactorActual.getBankcode()).getBankname());
					factorScoreCardVO.setFactorid(bankfactorActual.getFactorid());
					bankScoreCardVO.setBankcode(bankfactorActual.getBankcode());
					
					BankFactors factor = factorMap.get(bankfactorActual
							.getFactorid());
					Double score = 0.0;
					if (factor != null ) {
						if(factor.getExpectedvalue() != null && factor.getExpectedvalue() > 0){
				    		LOG.info("inside IF" + factor.getExpectedvalue());
				    		LOG.debug("inside IF" + factor.getExpectedvalue());
				//				bankScoreCardVO.setExpectedValue(factor.getExpectedvalue());
					//			bankScoreCardVO.setActualValue(bankfactorActual.getActualvalue());
								score = ( (bankfactorActual.getActualvalue() *100.0/ factor.getExpectedvalue()));	//* factor.getWeightage();
								bankScoreCardVO.setScore(score);
								bankScoreCardVO.setRank(determineRank(score));
						}else{
				    		LOG.info("inside else" + bankfactorActual.getActualvalue());
				    		LOG.debug("inside else" + bankfactorActual.getActualvalue());
							bankScoreCardVO.setRank(bankfactorActual.getActualvalue());						
						}
					} 
					bankScoreCards.add(bankScoreCardVO);
					Date fromDt = bankfactorActual.getFromdt();
					if(fromDt != null && !factorTimeMap.containsKey(fromDt)){
						factorTimeMap.put(fromDt, fromDt);
						FactorTimeVO factorTimeVO = new FactorTimeVO();
						factorTimeVO.setFromdt(fromDt);
						factorTimeVO.setTodt(bankfactorActual.getTodt());
						factorTimeList.add(factorTimeVO);
					}
				}
				factorScoreCardVO.setBankScoreCards(bankScoreCards);
			}
			factorScoreCardVOs.add(factorScoreCardVO);
		}
		if(out!=null && "xml".equals(out)){
			try {
				r.getWriter().append(XMLUtil.serializeReportXml(factorScoreCardVOs, searchVO));
			} catch (IOException e) {
				e.printStackTrace();
			} 
		}
		else{
			view="search/result";
			model.addAttribute("factorTimeList", factorTimeList);
			model.addAttribute("result", factorScoreCardVOs);
			model.addAttribute("banks", banks);
			model.addAttribute("bankSize", banks.size());
	//	}
	//	 return view;
	}

	private void convertSurveyToBankActual(
			List<BankFactorsActual> bankFactorsActualList,
			List<SurveyAnswers> surveyAnswersActualList) {
		for(SurveyAnswers surveyAnswers: surveyAnswersActualList){
			BankFactorsActual bankFactorsActual = new BankFactorsActual();
			bankFactorsActual.setBankcode(surveyAnswers.getBankcode());
			bankFactorsActual.setFactorid(surveyAnswers.getFactorid());
			bankFactorsActual.setFactorName(surveyAnswers.getFactorName());
			bankFactorsActual.setFromdt(surveyAnswers.getStartdate());
			bankFactorsActual.setTodt(surveyAnswers.getEnddate());
			bankFactorsActual.setActualvalue(Integer.parseInt(surveyAnswers.getAnswercode()));
			bankFactorsActual.setAnswerDesc(surveyAnswers.getAnswerdescription());
			bankFactorsActualList.add(bankFactorsActual);
		}
	}*/
	@RequestMapping(value = "/search/graphdummy", method = RequestMethod.GET)
	public void graphdummy(SearchVO searchVO, Model model, HttpServletRequest r){
		HttpSession session = r.getSession();
		session.setAttribute("searchVO", searchVO);
	}
	@RequestMapping(value = "/search/graph", method = RequestMethod.GET)
	public void graph(HttpServletRequest r, HttpServletResponse rs, Model model) throws JAXBException, IOException{
		HttpSession session = r.getSession();
		SearchVO searchVO = (SearchVO)session.getAttribute("searchVO");
		HashMap<Date, Date> factorTimeMap = new HashMap<Date, Date>();
		List<FactorTimeVO> factorTimeList = formFactorTimeList(searchVO,
				factorTimeMap);		
		FactorTimerListVO factorTimerListVO = new FactorTimerListVO();
		for(FactorTimeVO factorTimeVO:factorTimeList){
			factorTimeVO.setBankFactorActualList(bankFactorsActualDAO.factorsForGraph(searchVO.getBankIds(), 
					searchVO.getFactorsIds(), factorTimeVO.getFromdt(), factorTimeVO.getTodt()));
		}
		factorTimerListVO.setFactorTimeList(factorTimeList);
		LOG.debug(factorTimeList);
		// create JAXB context and instantiate marshaller
		JAXBContext context = JAXBContext.newInstance(FactorTimerListVO.class);
		Marshaller m = context.createMarshaller();
		m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
		m.marshal(factorTimerListVO, System.out);
		StringWriter sr= new StringWriter();
		m.setProperty("jaxb.formatted.output",new Boolean(true)); 
		m.marshal(factorTimerListVO, sr);	
		rs.setContentType("text/html;charset=UTF-8");
	    rs.getWriter().append(sr.toString());
		session.removeAttribute("searchVO");
		model.addAttribute("scorecardGraph",sr.toString().replaceAll("\"", "'"));
				//r.getQueryString().replaceAll("&", ";")+";out=xml");
	}
		
	private int determineRank(Double score){
		int rank=0; 
		if(score <=24){rank=1;
		}else if(score>24 &&  score<=72){rank=2;
		}else if(score>72 &&  score<=120){rank=3;
		}else if(score>120 &&  score<=168){rank=4;
		}else if(score>168 &&  score<=216){rank=5;		
		}else if(score>216){rank=6;
		}
		return rank;
	}
	@RequestMapping(value = "/search/result", method = RequestMethod.GET)
	public void result(SearchVO searchVO, Model model) {
		HashMap<Date, Date> factorTimeMap = new HashMap<Date, Date>();
		List<FactorTimeVO> factorTimeList = formFactorTimeList(searchVO,
				factorTimeMap);
		formBankResultList(searchVO, factorTimeList);
		HashMap<String, String> factorIdMap = new HashMap<String, String>();
		for(String factorIds: searchVO.getFactorsIds()){
			factorIdMap.put(factorIds, factorIds);		
		}
		List<Factors> activeFactorsList=factorsDAO.selectAllFactors();
		for(FactorTimeVO factorTimeVO:factorTimeList){
			List<BankResultVO> bankResultList = factorTimeVO.getBankResultList();
			for(BankResultVO bankResultVO:bankResultList){
				List<String> bankIds = new ArrayList<String>();
				bankIds.add(bankResultVO.getBankCode());
				List<BankFactors> periodList = bankFactorsDAO.bankFactorsByBankCodes(bankIds, factorTimeVO.getFromdt(),factorTimeVO.getTodt());
				List<FactorScoreCardVO> factorScoreCardList = new ArrayList<FactorScoreCardVO>();
				for(Factors factors:activeFactorsList){
					LOG.debug("FacorIDMap"+factorIdMap);
					LOG.debug("FacorID from active"+factors.getFactorid());
					if(factorIdMap.containsKey(factors.getFactorid().toString())){
						LOG.debug("Inside if loop setting factorScoreCard");
						FactorScoreCardVO factorScoreCardVO = new FactorScoreCardVO();
						factorScoreCardVO.setFactorid(factors.getFactorid());
						factorScoreCardVO.setFactorName(factors.getFactorname());
						factorScoreCardVO.setRank(calculateRank(bankResultVO.getBankCode(),factorScoreCardVO.getFactorid(),factorTimeVO.getFromdt(),factorTimeVO.getTodt(),periodList));
						factorScoreCardList.add(factorScoreCardVO);
					}
				}
				bankResultVO.setFactorScoreCardList(factorScoreCardList);
			}
		}
		FactorTimerListVO factorTimerListVO = new FactorTimerListVO();
		factorTimerListVO.setFactorTimeList(factorTimeList);
		model.addAttribute("factorTimeList", factorTimeList);
		
		
	}

	private String calculateRank(String bankCode, Integer factorid,
			Date fromdt, Date todt, List<BankFactors> periodList) {
		String rank="0";
		LOG.debug("periodLIst"+periodList);
		LOG.debug("factorID slfslfks"+factorid);
		for(BankFactors bankFactors:periodList){
			if(factorid.equals(bankFactors.getFactorid())){
				LOG.debug("inside if for bankfactorsactual");
				if(bankFactors.getExpectedvalue() != null && bankFactors.getExpectedvalue() > 0){
					Integer actualValue = bankFactorsActualDAO
					.bankFactorsActualByFactor(bankCode, factorid.toString(), fromdt,
							todt);
					Double score = (actualValue *100.0/ bankFactors.getExpectedvalue());
					rank = determineRank(score)+"";
				}else{
					rank = surveyAnswersDAO
					.surveyAnswersByFactor(bankCode, factorid.toString(), fromdt,
							todt);					
				}
			}
		}
		return rank;
	}

	private void formBankResultList(SearchVO searchVO,
			List<FactorTimeVO> factorTimeList) {
		HashMap<String, String> bankCodeMap = new HashMap<String, String>();
		for(String bankIds: searchVO.getBankIds()){
			bankCodeMap.put(bankIds, bankIds);
		}
		List<BankDetails> activeBankDetails =  bankDetailsDAO
		.selectAllAuthorizedBankDetails(SecurityContextHolder
				.getContext().getAuthentication().getName());			
		for(FactorTimeVO factorTimeVO:factorTimeList){
			List<BankResultVO> bankResultList = new ArrayList<BankResultVO>();
			for (BankDetails bankDetails: activeBankDetails){
				if(bankCodeMap.containsKey(bankDetails.getBankcode())){
					BankResultVO bankResultVO = new BankResultVO();
					bankResultVO.setBankCode(bankDetails.getBankcode());
					bankResultVO.setBankName(bankDetails.getBankname());
					bankResultVO.setBankComments(surveyAnswersDAO
								.surveyAnswersByBankCode(bankDetails.getBankcode(), factorTimeVO.getFromdt(),
										factorTimeVO.getTodt()));
					bankResultList.add(bankResultVO);
				}
			}
			factorTimeVO.setBankResultList(bankResultList);
		}
	}

	private List<FactorTimeVO> formFactorTimeList(SearchVO searchVO,
			HashMap<Date, Date> factorTimeMap) {
		List<FactorTimeVO> factorTimeList = new ArrayList<FactorTimeVO>();		
		LOG.debug("fromDate = "+searchVO.getFromDt());
		LOG.debug("toDate = "+searchVO.getToDt());		
		Date fromDate=searchVO.getFromDt();
		Date toDate = searchVO.getToDt();
		List<String> bankIds = searchVO.getBankIds();
		List<BankFactorsActual> periodList = bankFactorsActualDAO.bankFactorsActualByBankCode(bankIds, fromDate, toDate);
		for(BankFactorsActual bankFactorsactual:periodList){
			Date fromDt = bankFactorsactual.getFromdt();
			Date toDt = bankFactorsactual.getTodt();
			if(fromDt != null && !factorTimeMap.containsKey(fromDt)){
				factorTimeMap.put(fromDt, fromDt);
				FactorTimeVO factorTimeVO = new FactorTimeVO();
				factorTimeVO.setFromdt(fromDt);
				factorTimeVO.setTodt(toDt);
				factorTimeList.add(factorTimeVO);
			}
		}
		return factorTimeList;
	}	
}
